/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package niseeDatabase;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import javax.imageio.ImageIO;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import javax.persistence.Query;
import niseeEntity.NiseeAnswer;
import niseeEntity.NiseeImage;
import niseeEntity.NiseeTestGroup;
import niseeEntity.NiseeTestSingle;
import niseeEntity.NiseeUser;

import niseeImageGenerator.ImageGenerator;
import niseeImageGenerator.niCircle;
import niseeImageGenerator.niShape;

/**
 *
 * @author Crespo
 */
public class niseeDB {

    private String PERSISTENCE_UNIT_NAME = "NiSeePU";
    private EntityManagerFactory emf;
    private EntityManager em;
    private static String MAXID = "SELECT MAX(n.imageIMAGEID) FROM NiseeImage n";
    private static String IDs = "SELECT n.imageIMAGEID FROM NiseeImage n";
    private static String MAXGROUP = "SELECT MAX(n.testGROUP) FROM NiseeTestGroup n WHERE n.userUSERNAME = :userUSERNAME";
    private static String CLEANGROUP = "DELETE  FROM NiseeTestGroup n WHERE n.testGROUPID = :testGROUPID";
    //private static String TYPE = "SELECT * FROM ? WHERE testTYPE=";
    //private static String TYPEID = "SELECT ? FROM ? WHERE TYPEID=";

    public niseeDB() {

        emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        em = emf.createEntityManager();
    }

    public EntityManager getEntityManager() {
        return em;
    }

    public void refresh(Object torefresh) {
        em.refresh(torefresh);

    }

    public int storeImage(byte[] imagedata) {
        NiseeImage img = new NiseeImage();
        img.setImageIMAGEFILE(imagedata);
        em.getTransaction().begin();
        em.persist(img);
        em.getTransaction().commit();

        return img.getImageIMAGEID();

    }

    public void cleanGroup(int id) {
        em.getTransaction().begin();
        NiseeTestGroup delete = em.find(NiseeTestGroup.class, id);
        em.remove(delete);
        em.getTransaction().commit();
    }

    public NiseeTestGroup getGroup(int id) {
        Query q = null;
        q = em.createNamedQuery("NiseeTestGroup.findByTestGROUPID");
        q.setParameter("testGROUPID", id);
        NiseeTestGroup group = null;
        try {
            group = (NiseeTestGroup) q.getSingleResult();
        } catch (NoResultException e) {
            System.out.println(e);
            return null;
        }
        return group;

    }

    public NiseeAnswer getAnswer(int image_id, String type) {
        Query q = null;
        q = em.createNamedQuery("NiseeAnswer.findByImageIMAGEIDandTYPE");
        q.setParameter("imageIMAGEID", image_id);
        q.setParameter("imageTYPE", type);
        NiseeAnswer ans = null;
        try {
            ans = (NiseeAnswer) q.getSingleResult();
        } catch (NoResultException e) {
            System.out.println(e);
            return null;

        }
        return ans;
    }

    public void cleanUnfinished(NiseeUser user) {

        for (NiseeTestGroup toclean : user.getNiseeTestGroupCollection()) {
            if (toclean.getTestDIAGNOSIS().equalsIgnoreCase("unsaved")) {
                em.getTransaction().begin();
                NiseeTestGroup clean = em.find(NiseeTestGroup.class, toclean.getTestGROUPID());
                em.remove(clean);
                em.getTransaction().commit();

            }

        }

    }

    public NiseeTestGroup quickStart(NiseeUser usr, int total) {

        int maxGroup = maxGroup(usr) + 1;
        em.getTransaction().begin();
        NiseeTestGroup group = new NiseeTestGroup();
        System.out.println("Curr Date + " + getDate());

        group.setTestDATE(getDate());
        group.setTestDIAGNOSIS("unsaved");
        group.setNiseeUser(usr);
        group.setTestGROUP(maxGroup);
        em.persist(group);
        em.getTransaction().commit();

        Query q = em.createQuery(IDs);
        List<Integer> ids = q.getResultList();
        if (total > ids.size()) {
            total = ids.size();
        }
        Collections.shuffle(ids);
        ids = ids.subList(0, total);
        Collection<NiseeTestSingle> singles = group.getNiseeTestSingleCollection();
        NiseeTestSingle single;
        for (Integer s : ids) {
            single = new NiseeTestSingle(s.intValue(), group.getTestGROUPID());
            singles.add(single);
        }
        em.getTransaction().begin();
        NiseeTestGroup newgroup = em.find(NiseeTestGroup.class, group.getTestGROUPID());
        newgroup.setNiseeTestSingleCollection(singles);
        em.getTransaction().commit();
        return group;
    }

    //could pass typeID instead of testType
    public NiseeTestGroup newTest(NiseeUser usr, String testType) {
        int maxGroup = maxGroup(usr) + 1;
        em.getTransaction().begin();
        NiseeTestGroup group = new NiseeTestGroup();
        System.out.println("Curr Date + " + getDate());

        group.setTestDATE(getDate());
        group.setTestDIAGNOSIS("unsaved");
        group.setNiseeUser(usr);
        group.setTestGROUP(maxGroup);
        em.persist(group);
        em.getTransaction().commit();

        // get typeID using testType
        /*Query q = em.createQuery(TYPE + testType);
        int typeID = (Integer) q.getSingleResult();

        // get all shape_IMAGE_ID where typeID
        q = em.createQuery(TYPEID + typeID);
        List<Integer> ids = q.getResultList();
        Collections.shuffle(ids);*/

        Collection<NiseeTestSingle> singles = group.getNiseeTestSingleCollection();
        NiseeTestSingle single;

        //for each shape_IMAGE_ID - retrieve information to create image
        ImageGenerator generator = new ImageGenerator();
        //for (Integer s : ids) {
        int format = 0, gap = 0, numberOfForegrounds = 0;
        ArrayList percentages = new ArrayList();
        ArrayList sizes = new ArrayList();
        ArrayList theFirstForeground = null;
        ArrayList theSecondForeground = null;
        Color foreground1Colour = null, foreground2Colour = null, backgroundColour = null;

        //get int format, gap, numberOfForegrounds with shape_IMAGE_ID=s.intValue()
        //get ArrayList percentages, sizes with shape_IMAGE_ID=s.intValue()
        //get theFirstForeground, theSecondForeground  with shape_IMAGE_ID=s.intValue()
        //get Color foreground1Colour, foreground2Colour, backgroundColour  with shape_IMAGE_ID=s.intValue()

        //----
        //using some default values until we can retrieve actual values
        format = 2;
        gap = 1;
        numberOfForegrounds = 1;
        percentages.add(20);
        percentages.add(27);
        percentages.add(29);
        sizes.add(15);
        sizes.add(10);
        sizes.add(5);
        foreground1Colour = Color.red;//can make with new Color(red, green, blue)
        backgroundColour = Color.black;
        //----
        
        //for all records where shape_IMAGE_ID=s retrieve shape_COOR_X,shape_COOR_Y,shape_SCALE
        /*for ()  {
            int x,y,scale;
            niShape shape = new niShape(x,y,scale);
            theFirstForeground.add(shape);
        }*/
        
        BufferedImage buffer = generator.CreateImage(theFirstForeground, theSecondForeground, format, percentages, sizes, gap, foreground1Colour, foreground2Colour, backgroundColour);
        //write to bytes
        //byte[] imageBytes = ((DataBufferByte) (buffer.getRaster().getDataBuffer())).getData();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            ImageIO.write(buffer, "jpg", baos);
        } catch (IOException e) {
        }
        byte[] imageBytes = baos.toByteArray();

        //test bytes
        /*InputStream in = new ByteArrayInputStream(imageBytes);
        try {
        File theImg = new File("atest_out.JPG");
        BufferedImage image = javax.imageio.ImageIO.read(in);
        ImageIO.write(image, "JPG", theImg);
        } catch (IOException e) {
        } catch (IllegalArgumentException e) {}*/

        //add image to DB
        int imageID = storeImage(imageBytes);
        //add to test
        single = new NiseeTestSingle(imageID, group.getTestGROUPID());
        singles.add(single);
        //}

        em.getTransaction().begin();
        NiseeTestGroup newgroup = em.find(NiseeTestGroup.class, group.getTestGROUPID());
        newgroup.setNiseeTestSingleCollection(singles);
        em.getTransaction().commit();
        return group;
    }

    public void saveProfile(NiseeUser user) {
        em.getTransaction().begin();
        NiseeUser toupdate = em.find(NiseeUser.class, user.getUserUSERNAME());
        toupdate.setUserEMAIL(user.getUserEMAIL());
        toupdate.setUserFAMILYNAME(user.getUserFAMILYNAME());
        toupdate.setUserFIRSTNAME(user.getUserFIRSTNAME());
        toupdate.setUserGENDER(user.getUserGENDER());
        toupdate.setUserDOB(java.sql.Date.valueOf(user.getUserDOB()));
        em.getTransaction().commit();

    }

    public void keepAnswer(HashMap<Integer, String> id_answer, int groupid) {
        NiseeTestGroup group = getGroup(groupid);
        em.getTransaction().begin();
        for (NiseeTestSingle single : group.getNiseeTestSingleCollection()) {
            int image_id = single.getNiseeTestSinglePK().getImageIMAGEID();
            String answer = id_answer.get(image_id);
            System.out.println("persistance image_id:" + image_id + " answer:" + answer);

            single.setUserANSWER(answer);
            em.persist(single);
        }
        NiseeTestGroup toupdate = em.find(NiseeTestGroup.class, groupid);
        toupdate.setTestDIAGNOSIS("diagnosis shoud be added");

        em.getTransaction().commit();

    }

    public void close() {
        em.close();
        emf.close();

    }

    public NiseeUser login(String username, String password) {
        if (username.isEmpty() || password.isEmpty()) {
            return null;
        }
        password = MD5toString(password);
        em = getEntityManager();
        Query q = null;
        q = em.createNamedQuery("NiseeUser.findByUserPASSWORDandUSERNAME");
        q.setParameter("userUSERNAME", username);
        q.setParameter("userPASSWORD", password);
//        System.out.println("username" +username + " passwd" + password );
        NiseeUser user = null;
        try {
            user = (NiseeUser) q.getSingleResult();

        } catch (NoResultException e) {

            return null;
        }
        return user;
    }

    public NiseeImage getImage(int id) {
        Query q = null;
        NiseeImage image;
        q = em.createNamedQuery("NiseeImage.findByImageIMAGEID");
        q.setParameter("imageIMAGEID", id);
        try {
            image = (NiseeImage) q.getSingleResult();
            System.out.println(image.getImageIMAGEID());

        } catch (NoResultException e) {
            return null;
        }
        return image;

    }

    public int maxGroup(NiseeUser user) {
        int max = 0;
        for (NiseeTestGroup group : user.getNiseeTestGroupCollection()) {
            if (group.getTestGROUP() > max) {
                max = group.getTestGROUP();
            }
        }

        return max;

    }

    public Date getDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd ");
        java.util.Date date = new java.util.Date();
        return date;


    }

    public static String MD5toString(String input) {

        String res = "";
        try {
            MessageDigest algorithm = MessageDigest.getInstance("MD5");
            algorithm.reset();
            algorithm.update(input.getBytes());
            byte[] md5 = algorithm.digest();
            String tmp = "";
            for (int i = 0; i < md5.length; i++) {
                tmp = (Integer.toHexString(0xFF & md5[i]));
                if (tmp.length() == 1) {
                    res += "0" + tmp;
                } else {
                    res += tmp;
                }
            }
        } catch (NoSuchAlgorithmException ex) {
            System.out.println(ex);
        }
        return res;
    }
}
